using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using Unity.Mathematics;
using UnityEngine.Scripting.APIUpdating;
using Features;
using UnityEngine.UI;
using DG.Tweening;
using Mono.Cecil;

public class Pawn : MonoBehaviour
{

    #region 组件引用
    public Property Property;
    public Card Card;
    public FeatureMono FeatureMono;
    public Roots Roots;
    public Slider HealthBar;
    public Image HealthBarImage;
    public SpriteRenderer CharaSprite;
    public PawnAnchor PawnAnchor;
    #endregion

    #region 动画
    public AttackAnim attackAnim;
    #endregion

    #region 数值
    private float attackInterval
    {
        get => 1.0f / (Property.AttackSpeed + 0.0000001f);
    }
    // public float maxHP;

    public bool campIsSelf
    {
        set
        {
            //HealthBarImage.color = value ? Color.green : Color.red;
            CharaSprite.transform.localScale = value ? new Vector3(-1f, 1f, 1f) : new Vector3(1f, 1f, 1f);
            _campIsSelf = value;
        }
        get
        {
            return _campIsSelf;
        }
    }
    private bool _campIsSelf;
    public GridNode gridNode;

    [HideInInspector]
    public bool ifHero = false;

    private float HP
    {
        get => Property.HealPoint;
        set => Property.HealPoint = value;
    }

    public int AttackNum = 1;

    public CardData TestCardData;

    /// <summary>
    /// 0.测试用初始化卡牌
    /// </summary>
    [ContextMenu("使用挂载的Data初始化")]
    public void InitByCardData()
    {
        Card = new Card();
        Card.CurrentPawn = this;

        Card.Attack = TestCardData.Attack;
        Card.AttackSpeed = TestCardData.AttackSpeed;
        Card.Defence = TestCardData.Defence;
        Card.Range = TestCardData.Range;
        Card.HealPoint = TestCardData.HealPoint;
        Card.Speed = TestCardData.Speed;
        Card.Description = TestCardData.Description;
        Card.ifHero = TestCardData.ifHero;
        ifHero = Card.ifHero;

        foreach (var feature in TestCardData.Features)
        {
            Card.Features.Add(Instantiate(feature));
        }
        foreach (var feature in TestCardData.RootFeatures)
        {
            Card.RootFeatures.Add(Instantiate(feature));
        }
        InitByCard();
    }

    /// <summary>
    /// 1.第一次生成、战斗开始前、战斗结束时依照Card初始化Pawn数据
    /// </summary>
    public void InitByCard()
    {
        ifHero = Card.ifHero;
        if (ifHero)
            return;
        Property.InitByCard(Card);
        FeatureMono.InitFeaturesByCard(Card);

        // DeckMono 预设卡组 CardData list
        // CardData => 初始卡组 （一堆的Card 和对应的 Pawn实例setactive false)
        // GameStart
        // Place
        // PlaceEnd
        // 每个Pawn调用InitByCard
        // Root效果应用
        // PawnFeatureInit
        // BattleStart
        // 回合开始效果应用
        // BattleEnd
    }

    // 2.Root生效
    public void ExecuteRoots()
    {
        Roots.ExecuteRoots(gridNode.layer, gridNode.number);
    }

    /// <summary>
    /// 3.战斗开始前初始化监听
    /// </summary>
    public void InitFeaturesListen()
    {
        FeatureMono.InitFeatures();
    }

    #endregion


    // Start is called before the first frame update
    protected void Start()
    {
        // HP = Card.HealPoint;
        // attackAnim = Resources.Load<AttackAnim>("Animation/AttackAnimClose");

        originalPosition = CharaSprite.transform.localPosition;
        originalRotation = CharaSprite.transform.localRotation;
    }

    // Update is called once per frame
    protected void Update()
    {

    }

    private float nextAttackWaitTime;
    IEnumerator AttackCoroutine()
    {
        nextAttackWaitTime = UnityEngine.Random.Range(attackInterval / 4.0f, attackInterval / 2.0f);
        yield return new WaitForSeconds(nextAttackWaitTime);
        while (HP > 0)
        {
            nextAttackWaitTime = attackInterval;
            Attack();
            yield return new WaitForSeconds(nextAttackWaitTime);
        }
    }

    IEnumerator DieCoroutine()
    {
        yield return null;
        Destroy(gameObject);
    }

    #region 行为
    public void OnStart()
    {
        OnStartEvent?.Invoke(new FeatureEventArgs() { pawn = this, TargetGridNode = gridNode });
        StartCoroutine(AttackCoroutine());
        StartCoroutine(BattleCoroutine());
    }

    protected void Attack()
    {
        List<Pawn> targets = new List<Pawn>();
        List<GridNode> enemys;

        if (Property.Range >= 2)
        {
            enemys = GridManager.instance.GetNodesByRange(RangeSelectors.ArcherRangeSelector, campIsSelf, gridNode);
        }
        else
        {
            enemys = GridManager.instance.GetNodesByRange(RangeSelectors.WarriorRangeSelector, campIsSelf, gridNode);
        }

        foreach (GridNode enemy in enemys)
        {
            var targetPawn = enemy.Pawn;
            if (targetPawn == null || !(targetPawn.campIsSelf ^ this.campIsSelf))
            {
                continue;
            }
            if (targetPawn.FeatureMono.IfHasFeature(typeof(Features.Taunts)))
            {
                targets.Clear();
                targets.Add(targetPawn);
                enemy.Pawn.OnDeadEvent += KillOne;
                break;
            }
            else
            {
                targets.Add(targetPawn);
            }
        }

        if (targets.Count == 0)
        {
            Move();
            return;
        }

        if (FeatureMono.IfHasFeature(typeof(Features.Assassin)))
        {
            targets.Sort((t1, t2) =>
            {
                return t1.HP.CompareTo(t2.HP);
            });
        }
        else
        {
            targets.Sort((t1, t2) =>
            {
                int d1
                    = math.abs(t1.gridNode.layer - this.gridNode.layer) * 100
                    + math.abs(t1.gridNode.number - this.gridNode.number) * 10
                    + ((t1.gridNode.number < this.gridNode.number) ? 0 : 1);
                int d2
                    = math.abs(t1.gridNode.layer - this.gridNode.layer) * 100
                    + math.abs(t1.gridNode.number - this.gridNode.number) * 10
                    + ((t1.gridNode.number < this.gridNode.number) ? 0 : 1);
                return d1.CompareTo(d2);
            });
        }

        attackAnim.PlayAnim(this);
        int attackedNum = 0;

        if (Property.Range >= 2)
        {
            int num = UnityEngine.Random.Range(0, targets.Count);
            Pawn target = targets[num];

            StartCoroutine(AttackCoroutine(target));
        }
        else
        {
            foreach (var target in targets)
            {
                if (attackedNum >= AttackNum)
                    return;

                StartCoroutine(AttackCoroutine(target));

                attackedNum++;
            }
        }

        FeatureEventArgs args = new FeatureEventArgs();
        args.pawn = this;
        args.Attacker = this;
        args.Defencer = targets;
        args.Damage = Property.Attack - targets[0].Property.Defence >= 1 ? Property.Attack - targets[0].Property.Defence : 1;

        OnAttackEvent?.Invoke(args);
    }

    IEnumerator AttackCoroutine(Pawn target)
    {
        attackAnim.PlayEffect(this, target);

        yield return new WaitForSeconds(attackAnim.qianYao);

        target.OnDeadEvent += KillOne;
        target.BeHit(Property.Attack, this);
        target.OnDeadEvent -= KillOne;
    }

    IEnumerator BattleCoroutine()
    {
        while (true)
        {
            OnTimeUpEvent?.Invoke(new FeatureEventArgs() { pawn = this });
            yield return new WaitForEndOfFrame();
        }
    }

    private void Move()
    {
        if (ifHero)
            return;
        if (!GameManager.instance.ifHeroMode && gridNode.layer == 1)
        {
            return;
        }
        List<GridNode> fronts = GridManager.instance.GetNodesByRange(RangeSelectors.WarriorRangeSelector, campIsSelf, gridNode);
        List<GridNode> targets = new List<GridNode>();

        foreach (GridNode front in fronts)
        {
            if (front.Pawn == null)
            {
                targets.Add(front);
            }
        }

        if (targets.Count > 0)
        {
            int num = UnityEngine.Random.Range(0, targets.Count);
            GridNode target = targets[num];
            target.Pawn = this;
            this.gridNode.Pawn = null;
            this.gridNode = target;

            // this.transform.position = GridManager.instance.gridTransforms[GridManager.GetGridNum(target.layer, target.number)].position;
            StartCoroutine(JumpCoroutine(GridManager.instance.gridTransforms[GridManager.GetGridNum(target.layer, target.number)].position));

            nextAttackWaitTime = UnityEngine.Random.Range(attackInterval / 4.0f, attackInterval / 3.0f);
        }
    }

    IEnumerator JumpCoroutine(Vector3 newPos)
    {
        float jumpTime = 0.12f;
        Vector3 height = new Vector3(0f, 0.5f, -Mathf.Sqrt(3f) / 2f) * 1f;
        Vector3 mid = newPos.y > transform.position.y ? newPos + height : transform.position + height;
        mid.x = (newPos.x + transform.position.x) / 2f;
        transform.DOMoveX(newPos.x, jumpTime * 2f);//.SetEase(Ease.Linear);
        transform.DOMoveY(mid.y, jumpTime).SetEase(Ease.OutCubic);
        transform.DOMoveZ(mid.z, jumpTime).SetEase(Ease.OutCubic);
        yield return new WaitForSeconds(jumpTime);

        transform.DOMoveY(newPos.y, jumpTime).SetEase(Ease.InCubic);
        transform.DOMoveZ(newPos.z, jumpTime).SetEase(Ease.InCubic);
    }

    public void Heal(float healValue)
    {
        if (Property.HealPoint <= 0)
            return;
        Property.HealPoint += healValue;
        SpriteTextManager.NewEffectText(healValue.ToString(), transform.position.x, transform.position.y, Color.green);
    }

    public void BeHit(float damage, Pawn attacker)
    {
        if (Property.HealPoint <= 0)
            return;

        if (FeatureMono.IfHasFeature(typeof(Features.Taunts)))
        {
            //SpriteTextManager.NewEffectText("嘲讽", transform.position.x, transform.position.y, Color.blue);
        }

        OnBeHitEvent?.Invoke(new FeatureEventArgs() { Attacker = attacker, pawn = this });

        var damageFinal = damage - Property.Defence >= 1 ? damage - Property.Defence : 1;
        Property.HealPoint -= damageFinal;
        SpriteTextManager.NewDamageNumber(damageFinal, transform.position.x, transform.position.y);
        //UpdateHealthBar();
        if (Property.HealPoint <= 0)
            Dead();
    }

    //public void UpdateHealthBar()
    //{
    //    // Debug.Log(HealthBar);
    //    HealthBar.value = (float)(Property.HealPoint / Card.HealPoint);
    //}

    public void Dead()
    {
        OnDeadEvent?.Invoke(new FeatureEventArgs() { pawn = this, ExcessDamage = (-Property.HealPoint), TargetGridNode = gridNode });

        if (FeatureMono.IfHasFeature(typeof(Features.Resurrection)))
        {
            FeatureMono.RemoveFeature(typeof(Features.Resurrection));
            Property.HealPoint = 1;
            SpriteTextManager.NewEffectText("复生" + Property.HealPoint.ToString(), transform.position.x, transform.position.y, Color.green);
            return;
        }

        if (gridNode != null)
        {
            if (gridNode.Pawn == this)
                gridNode.Pawn = null;
        }
        gridNode = null;

        //SpriteTextManager.NewEffectText("死亡", transform.position.x, transform.position.y, Color.red);
        StartCoroutine(DeadCoroutine());
    }

    public void ResetOnBattleEnd()
    {
        DOTween.CompleteAll();
        if (campIsSelf)
        {
            FeatureMono.RemoveFeatures();
            CharaSprite.transform.localRotation = originalRotation;
            CharaSprite.transform.localPosition = originalPosition;
            CharaSprite.color = new Color(CharaSprite.color.r, CharaSprite.color.g, CharaSprite.color.b, 1);
            gameObject.SetActive(true);
            PawnAnchor.ReturnPosition();
            InitByCard();
            //SpriteTextManager.NewEffectText("复位", transform.position.x, transform.position.y, Color.blue);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    private Quaternion originalRotation;
    private Vector3 originalPosition;

    IEnumerator DeadCoroutine()
    {
        float deadTime = 0.3f;
        float lyingTIme = 0.2f;
        float fadeTime = 0.3f;

        float scaleX = campIsSelf ? -1f : 1f;
        Vector3 down = new Vector3(0f, 0.5f, -Mathf.Sqrt(3f) / 2f) * (-4f);
        Vector3 back = new Vector3(4f, 0f, 0f) * scaleX;

        CharaSprite.transform.DOKill();
        transform.DOKill();

        CharaSprite.transform.DOLocalRotate(new Vector3(-60f, 0f, -90f * scaleX), deadTime);
        CharaSprite.transform.DOLocalMove(CharaSprite.transform.localPosition + down + back, deadTime);
        yield return new WaitForSeconds(deadTime + lyingTIme);

        CharaSprite.DOFade(0, fadeTime);
        yield return new WaitForSeconds(fadeTime);

        if (campIsSelf)
        {
            DOTween.CompleteAll();
            gameObject.SetActive(false);
        }
        else
        {
            CheckIfEnd();
            DOTween.CompleteAll();
            Destroy(gameObject);
        }

        CheckIfEnd();
    }

    /// <summary>
    /// 1.单位死亡时通知关卡检查是否结束
    /// </summary>
    public void CheckIfEnd()
    {
        LevelManager.instance.OnPawnDeadCheckIfEnd();
    }

    /// <summary>
    /// 战斗结束调用
    /// </summary>
    [ContextMenu("复位")]
    public void Activate()
    {
        gameObject.SetActive(true);
        PawnAnchor.ReturnPosition();
        // 隐藏血条
    }

    public void KillOne(FeatureEventArgs args)
    {
        args.Attacker = this;
        OnKillEvent?.Invoke(args);
    }

    private void OnDestroy()
    {
        // Debug.Log(HP);
    }

    /// <summary>
    /// 6.战斗结束发个通知
    /// </summary>
    public void OnBattleOver()
    {
        StopAllCoroutines();
        ResetOnBattleEnd();
    }

    #endregion

    #region 委托列表
    public event Action<FeatureEventArgs> OnAttackEvent;
    public event Action<FeatureEventArgs> OnDeadEvent;
    public event Action<FeatureEventArgs> OnBeHitEvent;
    public event Action<FeatureEventArgs> OnStartEvent;
    public event Action<FeatureEventArgs> OnTimeUpEvent;
    public event Action<FeatureEventArgs> OnVictoryEvent;
    public event Action<FeatureEventArgs> OnKillEvent;
    // public event Action<FeatureEventArgs> OnPlacedEvent;
    #endregion
}
